package org.x.yuenovel.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.x.yuenovel.contants.CommonConstant;
import org.x.yuenovel.controller.param.RegisterParam;
import org.x.yuenovel.dao.UserInfoDao;
import org.x.yuenovel.domain.UserInfo;
import org.x.yuenovel.enums.ResultCodeEnum;
import org.x.yuenovel.enums.RoleEnum;
import org.x.yuenovel.exception.ApiException;
import org.x.yuenovel.exception.ApiExceptionAsserts;
import org.x.yuenovel.service.UserInfoService;
import org.x.yuenovel.util.JwtTokenUtil;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author xuezhendong
 * @date 2022/4/15 10:34 下午
 */
@Service
public class UserInfoServiceImpl implements UserInfoService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserInfoServiceImpl.class);

    @Resource
    private UserInfoDao userInfoDao;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    public UserInfo getUserInfoByMailOrName(String mail, String userName) {
        List<UserInfo> userInfoList = userInfoDao.getUserInfoListByMailOrName(mail, userName);
        return CollectionUtils.isEmpty(userInfoList) ? null : userInfoList.get(0);
    }

    @Override
    public String login(String username, String password) {
        ApiExceptionAsserts.hasText(username, ResultCodeEnum.USERNAME_REQUIRED);
        ApiExceptionAsserts.hasText(password, ResultCodeEnum.PASSWORD_REQUIRED);

        String token = null;
        Boolean enabled = null;

        try {
            UserInfo userDetails = (UserInfo) userDetailsService.loadUserByUsername(username);
            enabled = userDetails.isEnabled();

            if(!passwordEncoder.matches(password, userDetails.getPassword())){
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.warn("登录异常: {}", e.getMessage());
        }

        if(enabled != null && !enabled) {
           throw new ApiException(ResultCodeEnum.STATUS_LOCKED);
        }

        return token;
    }

    @Override
    public UserInfo queryUserByUsername(String username) {
        List<UserInfo> userInfoList = userInfoDao.queryUserByUsername(username);
        return userInfoList.get(0);
    }

    /**
     * 创建用户唯一方法，请勿新建
     *
     * @return boolean
     */
    private boolean createUser(UserInfo userInfo) {
        String userName = userInfo.getUsername().replace("\\s*", "");
        if (ObjectUtils.isEmpty(userName)
                || userName.length() < CommonConstant.USERNAME_LEN_MIN
                || userName.length() > CommonConstant.USERNAME_LEN_MAX) {
            throw new ApiException(ResultCodeEnum.USERNAME_LEN_ERROR);
        }
        String password = userInfo.getPassword().replace("\\s*", "");
        if (ObjectUtils.isEmpty(password)
                || password.length() < CommonConstant.PASSWORD_LEN_MIM
                || password.length() > CommonConstant.PASSWORD_LEN_MAX) {
            throw new ApiException(ResultCodeEnum.PASSWORD_LEN_ERROR);
        }
        if (null == RoleEnum.getAuthority(userInfo.getRole())) {
            throw new ApiException(ResultCodeEnum.ROLE_ERROR);
        }
        UserInfo has = getUserInfoByMailOrName(userInfo.getMail(), userInfo.getUsername());
        if (null != has) {
            if (has.getUsername().equals(userInfo.getUsername())) {
                throw new ApiException(ResultCodeEnum.USER_NAME_HAD);
            } else {
                throw new ApiException(ResultCodeEnum.EMAIL_HAD);
            }
        }
        userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
        return userInfoDao.createUser(userInfo) > 0;
    }

    @Override
    public Boolean register(RegisterParam registerParam) {
        UserInfo userInfo = new UserInfo();
        userInfo.setEnable(Boolean.TRUE);
        userInfo.setUsername(registerParam.getUsername());
        userInfo.setPassword(registerParam.getPassword());
        userInfo.setMail(registerParam.getMail());
        userInfo.setRole(RoleEnum.USER.getRole());
        return createUser(userInfo);
    }
}
